package com.tanjie.blackbean.orm.generate;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.IFill;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Property;
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;
import com.tanjie.blackbean.mybatis.common.CommonField;
import lombok.extern.slf4j.Slf4j;

import java.io.File;

import static com.tanjie.blackbean.orm.generate.GenerationConfig.outPutBasePath;

/**
 * @author: tanjie
 * @date: 2021-12-15
 **/
@Slf4j
public class CodeGenerator {

    AbstractTemplateEngine engine = new FreemarkerTemplateEngine();

    private final GenerationConfig config;

    public CodeGenerator(GenerationConfig generationConfig) {
        this.config = generationConfig;
    }

    public void execute() {
        new AutoGenerator(this.dataSourceConfigBuilder().build()) // 数据源
                // 全局配置
                .global(this.globalConfigBuilder().build())
                // 包配置
                .packageInfo(this.packageConfigBuilder().build())
                // 策略配置
                .strategy(this.strategyConfigBuilder().build())
                // 注入配置
                .injection(this.injectionConfigBuilder().build())
                // 模板配置
                .template(this.templateConfigBuilder().build())
                // 执行
                .execute(this.templateEngine());
    }

    // 配置数据源
    public IConfigBuilder<DataSourceConfig> dataSourceConfigBuilder() {
        return new DataSourceConfig.Builder(config.url, config.userName, config.password)
                .dbQuery(new MySqlQuery())
                .typeConvert(new MySqlTypeConvert())
                .keyWordsHandler(new MySqlKeyWordsHandler());
    }

    // 生成代码的包的路径配置
    public IConfigBuilder<PackageConfig> packageConfigBuilder() {
        return new PackageConfig.Builder()
                .entity("model")
                .parent(config.parentPackage) // 父级包路径
                .moduleName(config.modelName); // 模块名称
    }

    // 覆盖默认的模版文件配置
    public IConfigBuilder<TemplateConfig> templateConfigBuilder() {
        String templatesDir = config.templatesDir;
        return new TemplateConfig.Builder()
                .service(templatesDir + "service.java")
                .serviceImpl(templatesDir + "serviceImpl.java")
                .controller(templatesDir + "controller.java")
                .mapper(templatesDir + "mapper.java")
                .xml(templatesDir + "mapper.xml");
    }

    // 生成策略配置
    public IConfigBuilder<StrategyConfig> strategyConfigBuilder() {
        IFill[] tableFills = {
                new Property(CommonField.CREATE_TIME.getProperty(), FieldFill.INSERT),
                new Property(CommonField.CREATE_BY.getProperty(), FieldFill.INSERT),
                new Property(CommonField.UPDATE_TIME.getProperty(), FieldFill.INSERT_UPDATE),
                new Property(CommonField.UPDATE_BY.getProperty(), FieldFill.UPDATE),
        };

        return new StrategyConfig.Builder()
                .addTablePrefix(config.getRemovePrefix())
                .addInclude(config.getTables()) // 哪些表
                .enableSkipView()
                .entityBuilder()
                .enableRemoveIsPrefix()  // 移除表前缀
                .enableTableFieldAnnotation() // 字段注释
                .addTableFills(tableFills)
                //.superClass(BaseEntity.class)
                .enableLombok() // 使用lombok
                .idType(IdType.ASSIGN_UUID)
                .naming(NamingStrategy.underline_to_camel) // 字段名称映射规则
                .controllerBuilder()
                .enableRestStyle()
                .enableHyphenStyle() // 接口请求路径样式
                .serviceBuilder()
                //.superServiceClass(BaseService.class)
                //.superServiceImplClass(BaseServiceImpl.class)
                .mapperBuilder()
                .enableBaseResultMap()
                .enableBaseColumnList();
    }

    // 自定义生成文件
    public IConfigBuilder<InjectionConfig> injectionConfigBuilder() {

        String path = outPutBasePath + "/"
                + config.parentPackage.replace(".", "/") + "/"
                + config.modelName;

        InjectionConfig.Builder builder = new InjectionConfig.Builder().fileOverride();
        builder.beforeOutputFile((tableInfo, stringObjectMap) -> {
            try {
                String entityName = tableInfo.getEntityName();
                File entityPath = new File(path + "/model/");
                File servicePath = new File(path + "/service/");
                boolean isSuccess = entityPath.mkdirs();
                servicePath.mkdirs();
                log.info("创建目录{}，isSuccess：{}", entityPath, isSuccess);
                engine.writer(stringObjectMap, config.templatesDir + "entityDTO.java.ftl", new File(entityPath + "/" + entityName + "DTO.java"));
                engine.writer(stringObjectMap, config.templatesDir + "entityQuery.java.ftl", new File(entityPath + "/" + entityName + "Query.java"));
                engine.writer(stringObjectMap, config.templatesDir + "entityVO.java.ftl", new File(entityPath + "/" + entityName + "VO.java"));
                engine.writer(stringObjectMap, config.templatesDir + "daoService.java.ftl", new File(servicePath + "/" + entityName + "DaoService.java"));
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        return builder;
    }

    // 一些全局配置
    public IConfigBuilder<GlobalConfig> globalConfigBuilder() {
        log.info("\n输出文件目录：{}", outPutBasePath);
        return new GlobalConfig.Builder()
                .enableSwagger() // 开启swagger
                .outputDir(outPutBasePath)
                .author(config.author)
                .dateType(DateType.ONLY_DATE)
                .disableOpenDir();
    }

    // 配置模版渲染引擎
    public AbstractTemplateEngine templateEngine() {
        return engine;
    }

}
